package org.jdpf.core.paramserializer;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.jdpf.core.kernel.logging.ILogger;
import org.jdpf.core.kernel.logging.LoggerFactory;
import org.jdpf.core.paramserializer.services.IParamSerializer;
import org.jdpf.core.plugins.parameters.Parameters;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class ParamSerializer implements IParamSerializer {

	private static final ILogger logger = LoggerFactory.getDefault()
			.getLogger();

	private Document doc;

	private String xmlParamFile;

	private Element root;

	private DocumentBuilder docBuilder;

	public ParamSerializer() {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		docBuilder = null;
		try {
			docBuilder = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void serializeParam(Parameters param) {
		doc = docBuilder.newDocument();
		initializeDocument();
		Element el = doc.createElement("jdpf:JDPFNet");
		String xmlNetFile = "not used";
		el.appendChild(createCommonElement("File", xmlNetFile));
		root.appendChild(el);

		List<String> transitionsId = param.getPluginIdList();
		for (String transId : transitionsId) {
			Element parametersElement = doc.createElement("Parameters");
			parametersElement.setAttribute("transitionId", transId);
			List<String> parametersName = param.getParameterNames(transId);
			for (String paramName : parametersName) {
				String value = (String) param.getParameterValue(transId,
						paramName);
				if (paramName.equals("Logging")) {
					parametersElement.setAttribute("logging", value);
				} else {
					Element parameterElement = doc.createElement("Parameter");
					parameterElement.appendChild(createCommonElement("Name",
							paramName));
					parameterElement.appendChild(createCommonElement("Value",
							value));
					parametersElement.appendChild(parameterElement);
				}
			}
			root.appendChild(parametersElement);
		}

		finalizeXMLSerialization();
	}

	private void initializeDocument() {
		root = doc.createElement("jdpf:JDPFParameters");
		Attr jdpf = doc.createAttribute("xmlns:jdpf");
		jdpf.setNodeValue("http://www.jdpf.org/JDPFParameters");
		root.setAttributeNode(jdpf);
		Attr xsi = doc.createAttribute("xmlns:xsi");
		xsi.setNodeValue("http://www.w3.org/2001/XMLSchema-instance");
		root.setAttributeNode(xsi);
		Attr location = doc.createAttribute("xmlns:schemaLocation");
		location
				.setNodeValue("http://www.jdpf.org/JDPFParameters ../org.jdpf.core.paramloader/src/main/resources/JDPFParameters.xsd");
		root.setAttributeNode(location);
	}

	private void finalizeXMLSerialization() {
		doc.appendChild(root);
		try {
			Transformer transformer = TransformerFactory.newInstance()
					.newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.transform(new DOMSource(doc), new StreamResult(
					new FileOutputStream(xmlParamFile)));
		} catch (TransformerConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerFactoryConfigurationError e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (TransformerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		logger.log("[INFO] Parameters serialize to XML format in file "
				+ xmlParamFile);
	}

	private Element createCommonElement(String name, String text) {
		Element el = doc.createElement("jdpf:" + name);
		el.setTextContent(text);
		return el;
	}

	public String getXMLParamFile() {
		return xmlParamFile;
	}

	public void setXMLParamFile(String file) {
		if (file.endsWith(".xml"))
			this.xmlParamFile = file;
		else {
			this.xmlParamFile = file + ".xml";
		}
	}

}
